package internal

import (
	"crypto/md5"
	"fmt"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/name5566/leaf/log"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"talent.com/agency_im/common/msg"
	"talent.com/agency_im/common/pay"
	"talent.com/agency_im/common/pay/integrated"
	"talent.com/agency_im/common/platform"
	"talent.com/agency_im/common/user"
	"talent.com/agency_im/common/utils"
	"talent.com/agency_im/conf"
	"talent.com/agency_im/conf/g"
	"talent.com/agency_im/modules/core"
	"talent.com/server/durotar.git/tools/collection"
	"talent.com/server/durotar.git/tools/tz"
)

func init() {
	// 跨域配置
	corsConfig := cors.DefaultConfig()
	corsConfig.AllowAllOrigins = true
	corsConfig.AllowHeaders = append(corsConfig.AllowHeaders, "X-AUTH-TOKEN")
	corsConfig.AllowMethods = append(corsConfig.AllowMethods, "OPTION")
	engine.Use(cors.New(corsConfig))

	// 加载资源模板
	engine.LoadHTMLGlob("_templates/*")

	// 对外用户api
	engine.GET("/upload/token/", getUploadToken)        // 上传token
	engine.GET("/download/token/", getDownloadToken)    // 私有资源下载url
	engine.GET("/users/:id/", getUserInfo)              // 获取用户信息
	engine.POST("/users/blacklist/", addBlacklist)      // 获取用户信息
	engine.GET("/pay/pay_types/", getAgencyPayTypes)    // 获取代理可用的收款分类列表
	engine.POST("/pay/send_receipt/", sendReceipt)      // 代理发送收款账户给用户
	engine.POST("/remark/update/", setRemark)           // 设置备注
	engine.GET("/get_user_quick_reply/", getQuickReply) // 设置备注
	engine.POST("/complain/", addComplain)              // 投诉代理

	// 商户平台open api
	engine.POST("/open/get_token/", getToken)               // 获取token
	engine.POST("/open/update_user_info/", updateUserInfo)  // 更新用户信息
	engine.POST("/open/get_user_info/", getUserInfoForOpen) // 获取用户相关信息

	// 代理充值平台 api
	engine.GET("/open/pay/messages/topics/", listTopics)                  // 查询会话列表
	engine.GET("/open/pay/messages/topics/:id/", listTopicMessages)       // 查询单人会话消息列表
	engine.GET("/open/pay/messages/", listMessages)                       // 查询消息列表
	engine.POST("/open/pay/orders/notify/", notifyPayOrder)               // 订单通知
	engine.POST("/open/pay/complain/notify/", complainHandlerNotify)      // 代理投诉
	engine.POST("/open/pay/send_message_to_agency/", sendMessageToAgency) // 发消息

	// 运维管理api
	engine.GET("/internal/server/status/", getServerStatus) // 服务运行状态
}

func requiredLogin(c *gin.Context) (uint64, error) {
	var (
		token     string
		authToken *user.AuthToken
		err       error
	)

	token = c.GetHeader("X-AUTH-TOKEN")

	if authToken, err = user.GetAuthToken(token); err != nil {
		return 0, err
	}
	return authToken.UserID, nil
}

func getUserInfo(c *gin.Context) {
	var (
		req                verboseReq
		ur                 userResp
		currentUserID      uint64
		targetUser         *user.User
		targetUserPlatform *platform.Platform
		err                error
	)

	if currentUserID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	if err = c.ShouldBind(&req); err != nil {
		writeFailResp(c, 31, err.Error())
		return
	}

	var params IDUriPathParam
	if err = c.ShouldBindUri(&params); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	// TODO cache user
	if targetUser, err = user.GetUser(params.ID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	// TODO cache platform
	if targetUserPlatform, err = platform.GetPlatformByID(targetUser.PlatformID); err != nil {
		writeFailResp(c, 3, err.Error())
		return
	}
	// 如果当前是代理，则查看用户更详细信息, 比如玩家VIP等级
	if req.Verbose && targetUserPlatform.ID != conf.ServerConfig().Pay.AgencyPlatformID {
		// TODO 运营账号
		if playerInform, err := pay.GetPlayerInfo(targetUser.ID, currentUserID); err != nil {
			log.Error("Get Pay Player Info Error: %v", targetUser.ID)
		} else {
			ur.Level = playerInform.Level
			ur.SuccessOrderCount = playerInform.SuccessOrderCount
			ur.IsBlacklist = playerInform.IsBlacklist
		}

		if remark, err := user.GetRemark(currentUserID, targetUser.ID); err != nil {
			log.Error("Get Pay Player remark Info Error: %v", currentUserID, targetUser.ID)
		} else {
			if remark != nil {
				ur.Remark = remark.Name
			}
		}

		ur.Platform = platformResp{
			ID:   targetUserPlatform.PayMchID,
			Name: targetUserPlatform.Name,
		}
	}

	ur.ID = targetUser.ID
	ur.ThirdUserID = targetUser.ThirdUserID
	ur.Nickname = targetUser.Nickname
	ur.PortraitUri = targetUser.PortraitUri
	writeSuccessResp(c, ur)
}

func getUploadToken(c *gin.Context) {
	token := utils.GetImageUploadToken()
	writeSuccessResp(c, uploadTokenResp{
		Key:       token.Key,
		Token:     token.Token,
		Thumbnail: utils.GetImageDownloadURL(token.Key),
	})

}

func getDownloadToken(c *gin.Context) {
	var (
		req downloadTokenReq
	)
	if err := c.ShouldBind(&req); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}

	keys := strings.Split(req.Keys, ",")
	fmt.Println(keys, len(keys))
	var result = downloadUrlsResp{}
	for _, key := range keys {
		if key == "" {
			continue
		}
		result.Urls = append(result.Urls, downloadUrlResp{
			Key: key,
			Url: utils.GetImageDownloadURL(key),
		})
	}
	writeSuccessResp(c, result)
}

func getAgencyPayTypes(c *gin.Context) {
	var (
		req               queryAgencyPayTypesReq
		err               error
		loginUserID       uint64
		loginUser         *user.User
		loginUserPlatform *platform.Platform
	)

	if loginUserID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	if err = c.ShouldBind(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	if loginUser, err = user.GetUser(loginUserID); err != nil {
		writeFailResp(c, 31, err.Error())
		return
	}

	if loginUserPlatform, err = platform.GetPlatformByID(loginUser.PlatformID); err != nil {
		writeFailResp(c, 32, err.Error())
		return
	}

	var playerID, agencyID uint64
	if loginUserPlatform.ID == conf.ServerConfig().Pay.AgencyPlatformID {
		if req.PlayerID == 0 {
			writeFailResp(c, 33, "required param: player_id")
			return
		}
		playerID = req.PlayerID
		agencyID = loginUserID
	} else {
		if req.AgencyID == 0 {
			writeFailResp(c, 34, "required param: agency_id")
			return
		}
		playerID = loginUserID
		agencyID = req.AgencyID
	}

	var result *[]pay.PayType
	if result, err = pay.GetAgencyPayTypes(playerID, agencyID); err != nil {
		writeFailResp(c, 3, err.Error())
		return
	}
	writeSuccessResp(c, &map[string]interface{}{
		"payTypes": result,
	})
}

func sendReceipt(c *gin.Context) {
	var (
		req               sendReceiptReq
		err               error
		loginUserID       uint64
		loginUser         *user.User
		loginUserPlatform *platform.Platform
	)

	if loginUserID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	if err = c.ShouldBind(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	if loginUser, err = user.GetUser(loginUserID); err != nil {
		writeFailResp(c, 31, err.Error())
		return
	}

	if loginUserPlatform, err = platform.GetPlatformByID(loginUser.PlatformID); err != nil {
		writeFailResp(c, 32, err.Error())
		return
	}

	if loginUserPlatform.ID != conf.ServerConfig().Pay.AgencyPlatformID {
		writeFailResp(c, 33, "not valid operator")
		return
	}

	if err = integrated.ProcessSelectPayTypeByAgency(loginUserID, req.PlayerID, pay.PayType(req.PayType)); err != nil {
		writeFailResp(c, 34, err.Error())
		return
	}

}

func getToken(c *gin.Context) {
	var (
		req   authByOpenReq
		plat  *platform.Platform
		err   error
		token *user.AuthToken
	)

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	params := map[string]string{
		"app_id":    req.AppID,
		"user_id":   fmt.Sprintf("%v", req.UserID),
		"timestamp": fmt.Sprintf("%v", req.Timestamp),
	}

	if req.Nickname != "" {
		params["nickname"] = req.Nickname
	}
	if req.PortraitUri != "" {
		params["portrait_uri"] = req.PortraitUri
	}
	if req.LeavingTime != 0 {
		params["im_leaving_time"] = fmt.Sprintf("%v", req.LeavingTime)
	}

	if plat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	sign := signParameters(params, plat.AppKey)
	if !strings.EqualFold(sign, req.Sign) {
		writeFailResp(c, 3, "签名错误")
		return
	}

	u := &user.User{PlatformID: plat.ID, ThirdUserID: req.UserID, Nickname: req.Nickname, PortraitUri: req.PortraitUri, Status: true, LeavingTime: req.LeavingTime}
	if u, err = user.GetOrCreateUser(u); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}

	// 创建authToken
	if token, err = user.AddAuthToken(u.ID); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	resp := authByOpenResp{ID: u.ID, Token: token.Token}

	writeSuccessResp(c, resp)

}

func updateUserInfo(c *gin.Context) {
	var (
		req  updateUserInfoByOpenReq
		plat *platform.Platform
		u    *user.User
		err  error
	)

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	status := "False"
	if req.Status {
		status = "True"
	}

	params := map[string]string{
		"app_id":    req.AppID,
		"user_id":   fmt.Sprintf("%v", req.UserID),
		"status":    status,
		"timestamp": fmt.Sprintf("%v", req.Timestamp),
	}

	if req.Nickname != "" {
		params["nickname"] = req.Nickname
	}
	if req.PortraitUri != "" {
		params["portrait_uri"] = req.PortraitUri
	}
	if req.LeavingTime != 0 {
		params["im_leaving_time"] = fmt.Sprintf("%v", req.LeavingTime)
	}

	if plat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	sign := signParameters(params, plat.AppKey)
	if !strings.EqualFold(sign, req.Sign) {
		writeFailResp(c, 3, "签名错误")
		return
	}

	if u, err = user.GetUserByThirdInfo(plat.ID, req.UserID); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}

	if err = user.UpdateUserInfo(&user.User{ID: u.ID, Nickname: req.Nickname, PortraitUri: req.PortraitUri, Status: req.Status, LeavingTime: req.LeavingTime}); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	resp := &updateUserInfoByOpenResp{ID: u.ID}

	writeSuccessResp(c, resp)

}

func getUserInfoForOpen(c *gin.Context) {
	var (
		req  getUserInfoOpenReq
		plat *platform.Platform
		u    *user.User
		err  error
	)

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	params := map[string]string{
		"app_id":    req.AppID,
		"user_id":   fmt.Sprintf("%v", req.UserID),
		"timestamp": fmt.Sprintf("%v", req.Timestamp),
	}

	if plat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	sign := signParameters(params, plat.AppKey)
	if !strings.EqualFold(sign, req.Sign) {
		writeFailResp(c, 3, "签名错误")
		return
	}

	if u, err = user.GetUserByThirdInfo(plat.ID, req.UserID); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}

	var hasUnreadMsg = false
	if hasUnreadMsg, err = msg.HasUnreadMessages(u.ID); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	resp := &getUserInfoOpenResp{HasUnreadMsg: hasUnreadMsg}

	writeSuccessResp(c, resp)

}

func addBlacklist(c *gin.Context) {
	var (
		req        blacklistReq
		targetUser *user.User
		userID     uint64
		err        error
	)

	if userID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	if targetUser, err = user.GetUser(req.TargetID); err != nil {
		writeFailResp(c, 8, err.Error())
		return
	}

	if err = pay.AddBlacklist(userID, targetUser.ID, req.Remark); err != nil {
		writeFailResp(c, 9, err.Error())
		return
	}

	writeSuccessResp(c, nil)

}

func setRemark(c *gin.Context) {
	var (
		req        RemarkReq
		targetUser *user.User
		userID     uint64
		err        error
	)

	if userID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	if targetUser, err = user.GetUser(req.TargetID); err != nil {
		writeFailResp(c, 8, err.Error())
		return
	}

	if err = user.CreateOrUpdateRemark(&user.Remark{SourceID: userID, TargetID: targetUser.ID, Name: req.Name}); err != nil {
		writeFailResp(c, 9, err.Error())
		return
	}

	writeSuccessResp(c, nil)

}

func getQuickReply(c *gin.Context) {
	var (
		userID uint64
		err    error
	)

	if userID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	var result *[]pay.QuickReply

	if result, err = pay.GetUserQuickReply(userID); err != nil {
		writeFailResp(c, 3, err.Error())
		return
	}

	writeSuccessResp(c, &map[string]interface{}{
		"quick_reply": result,
	})

}

func addComplain(c *gin.Context) {
	var (
		req        ComplainReq
		targetUser *user.User
		userID     uint64
		err        error
		result     *pay.ComplainResp
	)

	if userID, err = requiredLogin(c); err != nil {
		writeFailResp(c, 30, err.Error())
		return
	}

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	if targetUser, err = user.GetUser(req.TargetID); err != nil {
		writeFailResp(c, 8, err.Error())
		return
	}

	if result, err = pay.ComplainUser(userID, targetUser.ID, req.ComplaintContent, req.ComplaintTypes, req.Images); err != nil {
		writeFailResp(c, 3, err.Error())
		return
	}

	m := &msg.Message{
		TopicType: int8(msg.TOPIC_TYPE_PRIVATE),
		SourceID:  conf.ServerConfig().Pay.PayOperatorID,
		TargetID:  userID,
		MsgType:   int8(msg.MSG_TYPE_TEXT),
		SendSelf:  false,
		Info:      result.MESSAGE,
	}
	core.SendMessage(m)

	writeSuccessResp(c, nil)
}

func listTopics(c *gin.Context) {
	var (
		req        listTopicsReq
		agencyPlat *platform.Platform
		playPlat   *platform.Platform
		agencyIDS  []uint64
		play       *user.User
		total      int
		topics     []msg.MessageTopic
		err        error
	)
	if err := c.ShouldBind(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	if agencyPlat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	if req.AgencyIDS != "" {
		var ids = strings.Split(req.AgencyIDS, ",")
		var ag *user.User
		var idStr string
		var idInt int
		for _, idStr = range ids {
			if idInt, err = strconv.Atoi(idStr); err != nil {
				writeFailResp(c, 3, err.Error())
				return
			}
			if ag, err = user.GetUserByThirdInfo(agencyPlat.ID, uint64(idInt)); err != nil {
				writeFailResp(c, 4, err.Error()+fmt.Sprintf(", Agency id: %v", idInt))
				return
			}

			if ag, err = user.GetUserByThirdInfo(agencyPlat.ID, uint64(idInt)); err != nil {
				writeFailResp(c, 5, err.Error())
				return
			} else {
				agencyIDS = append(agencyIDS, ag.ID)
			}
		}
	}

	if req.PlayMchID > 0 && req.PlayID > 0 {
		if playPlat, err = platform.GetPlatformByPayMchID(req.PlayMchID); err != nil {
			writeFailResp(c, 6, err.Error())
			return
		}
		if play, err = user.GetUserByThirdInfo(playPlat.ID, req.PlayID); err != nil {
			writeFailResp(c, 7, err.Error())
			return
		}
	}

	var playImID uint64 = 0
	if play != nil {
		playImID = play.ID
	}
	if total, topics, err = msg.ListTopics(req.ID, conf.ServerConfig().Pay.AgencyPlatformID, agencyIDS, playImID, req.StartUpdatedAt, req.EndUpdatedAt, req.IsReplied, req.PageNo, req.PageSize); err != nil {
		writeFailResp(c, 8, err.Error())
		return
	} else {
		var tsps []topicResp
		for _, t := range topics {
			var agencyIM *user.User
			if agencyIM, err = user.GetUser(t.UserID); err != nil {
				writeFailResp(c, 9, err.Error())
				return
			}
			var playIM *user.User
			if playIM, err = user.GetUser(t.TargetID); err != nil {
				writeFailResp(c, 10, err.Error())
				return
			}

			var payMch *platform.Platform
			if payMch, err = platform.GetPlatformByID(playIM.PlatformID); err != nil {
				writeFailResp(c, 11, err.Error())
				return
			}

			tsps = append(tsps, topicResp{
				ID:             t.ID,
				AgencyID:       agencyIM.ThirdUserID,
				PlayMchID:      payMch.PayMchID,
				PlayID:         playIM.ThirdUserID,
				UnreadMsgCount: int(t.MaxMsgID - t.ReadMsgID),
				IsReplied:      t.IsReplied,
				CreateAt:       AsiaTime(t.CreatedAt),
				UpdatedAt:      AsiaTime(t.UpdatedAt),
			})
		}
		result := &listTopicsResp{
			Total: total,
			List:  tsps,
		}
		writeSuccessResp(c, result)
	}
}

func listTopicMessages(c *gin.Context) {
	var (
		req listTopicMessagesReq
		//agencyPlat *platform.Platform
		agency   *user.User
		playPlat *platform.Platform
		play     *user.User
		topic    *msg.MessageTopic
		messages []msg.Message
		err      error
	)

	var idParams IDUriPathParam
	if err := c.ShouldBindUri(&idParams); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	if err := c.ShouldBind(&req); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	if _, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 3, err.Error())
		return
	}

	if topic, err = msg.GetTopicByID(idParams.ID); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}

	if agency, err = user.GetUser(topic.UserID); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	if agency.PlatformID != topic.UserPlatformID {
		writeFailResp(c, 6, fmt.Sprintf("user is not agency: %v", agency.ID))
		return
	}

	if play, err = user.GetUser(topic.TargetID); err != nil {
		writeFailResp(c, 8, err.Error())
		return
	}

	if playPlat, err = platform.GetPlatformByID(play.PlatformID); err != nil {
		writeFailResp(c, 7, err.Error())
		return
	}

	if messages, err = msg.FetchLatestMessagesInTopic(topic.TopicID, req.LastMsgID, req.PageSize); err != nil {
		writeFailResp(c, 9, err.Error())
		return
	}

	var result listTopicMessagesResp
	result.Agency = userResp{
		ID:          agency.ThirdUserID,
		Nickname:    agency.Nickname,
		PortraitUri: agency.PortraitUri,
	}

	result.Player = userResp{
		ID: play.ThirdUserID,
		Platform: platformResp{
			ID: playPlat.PayMchID,
		},
		Nickname:    play.Nickname,
		PortraitUri: play.PortraitUri,
	}

	var userMap = map[uint64]uint64{
		agency.ID: agency.ThirdUserID,
		play.ID:   play.ThirdUserID,
	}

	for _, m := range messages {
		result.List = append(result.List, messageResp{
			ID:        m.ID,
			SourceID:  userMap[m.SourceID],
			TargetID:  userMap[m.TargetID],
			MsgType:   m.MsgType,
			Info:      m.Info,
			CreateAt:  AsiaTime(m.CreatedAt),
			UpdatedAt: AsiaTime(m.UpdatedAt),
		})
	}

	writeSuccessResp(c, result)
}

func listMessages(c *gin.Context) {
	var (
		req        listMessagesReq
		agencyPlat *platform.Platform
		agency     *user.User
		playPlat   *platform.Platform
		play       *user.User
		messages   []msg.Message
		err        error
	)

	if err := c.ShouldBind(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	if agencyPlat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	if agency, err = user.GetUserByThirdInfo(agencyPlat.ID, uint64(req.AgencyID)); err != nil {
		writeFailResp(c, 3, err.Error())
		return
	}

	if playPlat, err = platform.GetPlatformByPayMchID(req.PlayMchID); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}
	if play, err = user.GetUserByThirdInfo(playPlat.ID, req.PlayID); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	topicID := msg.GetTopicID(int8(msg.TOPIC_TYPE_PRIVATE), agency.ID, play.ID)

	if messages, err = msg.FetchLatestMessagesInTopic(topicID, req.LastMsgID, req.PageSize); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	var result listTopicMessagesResp
	result.Agency = userResp{
		ID:          agency.ThirdUserID,
		Nickname:    agency.Nickname,
		PortraitUri: agency.PortraitUri,
	}

	result.Player = userResp{
		ID: play.ThirdUserID,
		Platform: platformResp{
			ID: playPlat.PayMchID,
		},
		Nickname:    play.Nickname,
		PortraitUri: play.PortraitUri,
	}

	var userMap = map[uint64]uint64{
		agency.ID: agency.ThirdUserID,
		play.ID:   play.ThirdUserID,
	}

	for _, m := range messages {
		result.List = append(result.List, messageResp{
			ID:        m.ID,
			SourceID:  userMap[m.SourceID],
			TargetID:  userMap[m.TargetID],
			MsgType:   m.MsgType,
			Info:      m.Info,
			CreateAt:  AsiaTime(m.CreatedAt),
			UpdatedAt: AsiaTime(m.UpdatedAt),
		})
	}

	writeSuccessResp(c, result)
}

func notifyPayOrder(c *gin.Context) {
	var (
		req      notifyPayOrderReq
		plat     *platform.Platform
		agency   *user.User
		playPlat *platform.Platform
		player   *user.User
		err      error
	)

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	params := map[string]string{
		"app_id":      req.AppID,
		"order_id":    fmt.Sprintf("%v", req.OrderID),
		"play_mch_id": fmt.Sprintf("%v", req.PlayMchID),
		"player_id":   fmt.Sprintf("%v", req.PlayID),
		"agency_id":   fmt.Sprintf("%v", req.AgencyID),
		"amount":      fmt.Sprintf("%v", req.Amount),
		"real_amount": fmt.Sprintf("%v", req.RealAmount),
		"message":     fmt.Sprintf("%v", req.Message),
		"timestamp":   fmt.Sprintf("%v", req.Timestamp),
	}

	if plat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	sign := signParameters(params, plat.AppKey)
	if !strings.EqualFold(sign, req.Sign) {
		writeFailResp(c, 3, "签名错误")
		return
	}

	if agency, err = user.GetUserByThirdInfo(plat.ID, req.AgencyID); err != nil {
		writeFailResp(c, 4, err.Error())
		return
	}

	if playPlat, err = platform.GetPlatformByPayMchID(req.PlayMchID); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	if player, err = user.GetUserByThirdInfo(playPlat.ID, req.PlayID); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	m := &msg.Message{
		TopicType: int8(msg.TOPIC_TYPE_PRIVATE),
		SourceID:  agency.ID,
		TargetID:  player.ID,
		MsgType:   int8(msg.MSG_TYPE_TEXT),
		SendSelf:  false,
		Info:      req.Message,
	}
	err = core.SendMessage(m)
	if err != nil {
		writeFailResp(c, 6, err.Error())
	}
	writeSuccessResp(c, nil)

}

func complainHandlerNotify(c *gin.Context) {
	var (
		req      complainNotifyReq
		plat     *platform.Platform
		playPlat *platform.Platform
		player   *user.User
		err      error
	)

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	params := map[string]string{
		"app_id":      req.AppID,
		"complain_id": fmt.Sprintf("%v", req.ComplainID),
		"play_mch_id": fmt.Sprintf("%v", req.PlayMchID),
		"player_id":   fmt.Sprintf("%v", req.PlayID),
		"agency_id":   fmt.Sprintf("%v", req.AgencyID),
		"message":     fmt.Sprintf("%v", req.Message),
		"timestamp":   fmt.Sprintf("%v", req.Timestamp),
	}

	if plat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	sign := signParameters(params, plat.AppKey)
	if !strings.EqualFold(sign, req.Sign) {
		writeFailResp(c, 3, "签名错误")
		return
	}

	if playPlat, err = platform.GetPlatformByPayMchID(req.PlayMchID); err != nil {
		writeFailResp(c, 5, err.Error())
		return
	}

	if player, err = user.GetUserByThirdInfo(playPlat.ID, req.PlayID); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	m := &msg.Message{
		TopicType: int8(msg.TOPIC_TYPE_PRIVATE),
		SourceID:  conf.ServerConfig().Pay.PayOperatorID,
		TargetID:  player.ID,
		MsgType:   int8(msg.MSG_TYPE_TEXT),
		SendSelf:  false,
		Info:      req.Message,
	}
	err = core.SendMessage(m)
	if err != nil {
		writeFailResp(c, 6, err.Error())
	}
	writeSuccessResp(c, nil)

}

func sendMessageToAgency(c *gin.Context) {
	var (
		req    SendMessageToAgencyReq
		err    error
		plat   *platform.Platform
		agency *user.User
	)

	if err = c.ShouldBindJSON(&req); err != nil {
		writeFailResp(c, 1, err.Error())
		return
	}

	params := map[string]string{
		"app_id":    req.AppID,
		"agency_id": fmt.Sprintf("%v", req.AgencyID),
		"message":   fmt.Sprintf("%v", req.Message),
		"timestamp": fmt.Sprintf("%v", req.Timestamp),
	}

	if plat, err = platform.GetPlatformByAppID(req.AppID); err != nil {
		writeFailResp(c, 2, err.Error())
		return
	}

	sign := signParameters(params, plat.AppKey)
	if !strings.EqualFold(sign, req.Sign) {
		writeFailResp(c, 3, "签名错误")
		return
	}

	if agency, err = user.GetUserByThirdInfo(plat.ID, req.AgencyID); err != nil {
		writeFailResp(c, 6, err.Error())
		return
	}

	m := &msg.Message{
		TopicType: int8(msg.TOPIC_TYPE_PRIVATE),
		SourceID:  conf.ServerConfig().Pay.PayOperatorID,
		TargetID:  agency.ID,
		MsgType:   int8(msg.MSG_TYPE_TEXT),
		SendSelf:  false,
		Info:      req.Message,
	}
	err = core.SendMessage(m)
	if err != nil {
		writeFailResp(c, 6, err.Error())
	}
	writeSuccessResp(c, nil)
}

func signParameters(params map[string]string, platformAppKey string) string {
	var keys []string
	for k := range params {
		keys = append(keys, k)
	}

	str := ""
	sort.Strings(keys)
	for _, k := range keys {
		str += fmt.Sprintf("%v=%v&", k, params[k])
	}
	str += fmt.Sprintf("key=%v", platformAppKey)
	return fmt.Sprintf("%x", md5.Sum([]byte(str)))
}

func getServerStatus(c *gin.Context) {
	c.HTML(http.StatusOK, "server_status.html", gin.H{
		"runSeconds": tz.GetNowTs() - g.StartTime,
		"usersCount": collection.CountSyncMap(g.AllAgents),
	})
}
